package fstools

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"syscall"

	"gitee.com/StarCitizen_CN/logger"
)

type GamePathCheckResult struct {
	Path string
	Err  error
}

// 缓存都放在这 注意初始化
func InitCacheDataDir(wd string) (err error) {
	dataDir := filepath.Join(wd, ".data_juice")
	L10nDownloadDir = filepath.Join(dataDir, "l10n_res")
	ContentDataDir = filepath.Join(dataDir, "content")
	TEMPDir = filepath.Join(dataDir, "temp")

	createArray := []string{dataDir, L10nDownloadDir, ContentDataDir}

	for _, path := range createArray {
		err = createHideDir(path)
		if err != nil {
			return
		}
	}

	return
}

func createHideDir(path string) (err error) {

	defer func(deferErr *error) {
		var catchErr = *deferErr
		if catchErr != nil {
			logger.ShowGuiMsg("创建目录时发生异常", catchErr.Error())
		}
	}(&err)

	if _, err := os.Stat(path); err != nil {
		if errors.Is(err, os.ErrExist) {
			err = nil
		}
		if errors.Is(err, os.ErrNotExist) {
			err = nil
		}
	}
	err = os.MkdirAll(path, os.ModeDir)
	if err != nil {
		logger.Err(err)
		return err
	}

	_ = HideFile(path)
	if _, err := os.Stat(path); err != nil {
		if errors.Is(err, os.ErrExist) {
			err = nil
			return nil
		} else {
			logger.Err(err)
			return err
		}

	}

	return nil
}

func HideFile(filename string) error {
	filenameW, err := syscall.UTF16PtrFromString(filename)
	if err != nil {
		return err
	}
	err = syscall.SetFileAttributes(filenameW, syscall.FILE_ATTRIBUTE_HIDDEN)
	if err != nil {
		return err
	}
	return nil
}

func GetL10NVersionName(gameRoot string) (isL10nInstalled bool, versionName string) {
	isCoreModuleInstalled := false
	isTextInstalled := false

	return isCoreModuleInstalled && isTextInstalled, "?"
}

func CheckGamePathAvaliable(path string) error {

	if _, checkErr := os.Stat(path); checkErr != nil {
		return checkErr
	}

	p4kPath := filepath.Join(path, "Data.p4k")
	gameExePath := filepath.Join(path, "Bin64\\StarCitizen.exe")

	if _, err := os.Stat(p4kPath); err != nil {
		logger.Err(err)
		return err
	}

	if _, err := os.Stat(gameExePath); err != nil {
		logger.Err(err)
		return err
	}

	return nil
}

// 如果还有其他寻录方式，请将过滤上移至调用者。
func GetAvaliableGameDirsFromLogs(paths []string, isOnlyLive bool) []string {

	logger.Debug("will search in these files:%v", paths)

	var uniquePaths []string
	var invalidPathIndexs []int
	for _, path := range paths {
		if _, err := os.Stat(path); err != nil {
			logger.Err(err)
			continue
		}

		gameLocations, logErr := getGameDirsByRsiLog(path, isOnlyLive)
		if logErr != nil {
			logger.Err(logErr)
			if !os.IsNotExist(logErr) {
				logger.Err(logErr)
			} else {
				logger.ShowGuiMsg("寻录发生异常", logErr.Error())
			}
			continue
		}

		for _, p := range gameLocations {
			count := 0
			for _, uniqueP := range uniquePaths {
				if p == uniqueP {
					count++
				}
			}

			if count != 0 {
				continue
			}

			logger.Debug("找到这个目录 %s，即将测试它！", p)
			uniquePaths = append(uniquePaths, p)

			// 注意移除的序列
			if err := CheckGamePathAvaliable(p); err != nil {
				logger.Debug("这个游戏路径内容不完整 %s： ", p)
				invalidPathIndexs = append(invalidPathIndexs, len(uniquePaths)-1)
				continue
			}
		}
	}

	logger.Debug("移除无效路径\n%v\n%v", uniquePaths, invalidPathIndexs)

	for i := len(invalidPathIndexs) - 1; i > -1; i-- {
		invalidIndex := invalidPathIndexs[i]
		uniquePaths = append(uniquePaths[:invalidIndex], uniquePaths[invalidIndex+1:]...)
	}

	logger.Debug("log 寻录完成, 寻找到如下目录: \n%v", uniquePaths)
	return uniquePaths
}

// 从启动器日志获取游戏目录 但是并未完成校验与去重
func getGameDirsByRsiLog(logPath string, isOnlyLive bool) (result []string, err error) {
	logger.Debug(logPath)
	defer func(result *[]string) {
		logger.Debug("针对 %s 的寻录完成, 寻找到如下目录：\n %s", logPath, *result)
	}(&result)

	logData, readLogErr := os.ReadFile(logPath)
	if readLogErr != nil {
		return result, readLogErr
	}

	if len(logData) == 0 {
		return []string{}, os.ErrInvalid
	}

	r := regexp.MustCompile(`[a-zA-Z]:\\\\.*StarCitizen[^/].LIVE`)
	var paths []string
	if isOnlyLive {
		paths = r.FindAllString(string(logData), -1)
	} else {
		paths = r.FindAllString(string(logData), -1)

		r = regexp.MustCompile(`[a-zA-Z]:\\\\.*StarCitizen[^/].PTU`)
		paths = append(paths, r.FindAllString(string(logData), -1)...)
	}

	result = paths
	return
}

func CheckoutAllRsiLogFiles() (paths []string) {
	defLogPath := os.Getenv("APPDATA") + "\\rsilauncher\\log.log"
	paths = append(paths, defLogPath)

	usersHome := filepath.Dir(os.Getenv("USERPROFILE"))
	relativeLogPath := strings.ReplaceAll(defLogPath, os.Getenv("USERPROFILE"), "")

	usersPath, err := os.ReadDir(usersHome)
	if err != nil {
		return paths
	}

	for _, userHome := range usersPath {
		if userHome.IsDir() {
			logPath := filepath.Join(userHome.Name(), relativeLogPath)
			_, err := os.Stat(logPath)
			if err != nil {
				continue
			} else {
				paths = append(paths, logPath)
			}
		}
	}

	return paths
}

func ScanTree(root string) (pathList []string, err error) {

	err = filepath.Walk(root,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				logger.Err(err)
				return err
			}

			if !info.IsDir() {
				pathList = append(pathList, path)
				fmt.Println(path, info.Size())
			}
			return nil
		})
	if err != nil {
		logger.Err(err)
		return
	}

	return
}
